package mainprogram;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import extraction.Categorie;
import extraction.Extraction;
import extraction.Tri;

/**
 * Cette classe va nous permettre d'avoir les différentes statistiques sur un fichier.
 * @author ejouini
 *
 */
public class Statistiques {

	
	/** Map qui contient pour une classe, ses statistiques. */
	private HashMap<String, Categorie> statsParClasses;

	/** Map qui va contenir par polarité, la liste des 20 mots les plus significatifs. */
	private HashMap<String, ArrayList<String>> motsPlusSignificatifs = null;
	
	/** Map qui va contenir par polarité, la liste des 20 mots les moins significatifs. */
	private HashMap<String, ArrayList<String>> motsMoinsSignificatifs = null;
	
	
	/**
	 * Méthode qui va lancer l'analyse d'un fichier dont le nom est passé en 
	 * paramètre.
	 * @param nomFichier : Nom du fichier à analyser
	 * @throws IOException
	 */
	public void analyseFichier (String nomFichier) throws IOException{
		Extraction e = new Extraction();
		statsParClasses = e.analyseFichier(nomFichier);
	}

	/**
	 * Méthode qui affiche les statistiques concernant toutes les classes de polarité :
	 * 		- Le nombre total de mots.
	 * 		- Le nombre de mots différents.
	 * 		- La longueur moyenne des tweets.
	 * 		- Les 20 mots les plus et les moins fréquents.
	 * 		- Les 20 mots les plus et les moins significatifs.
	 * @throws IOException 
	 */
	public void getStatTotales() throws IOException {
		HashMap<String, Integer> motsTotal = new HashMap<String, Integer>();
		double longueurMoyenne = 0;

		for (Categorie s : statsParClasses.values()){
			motsTotal.putAll(s.getMotsOcc());
			longueurMoyenne += s.longueurMoyenneTweet();
		}

		longueurMoyenne = longueurMoyenne / statsParClasses.size();

		System.out.println("Les statistiques toutes classes confondues sont : ");
		System.out.println("Le nombre de mots total est  : " + Categorie.getNbMotsTotal(motsTotal) );
		System.out.println("Le nombre de mots différents est : " + Categorie.getNbMotsDifferents(motsTotal));
		System.out.println("La longueur moyenne des tweet est de " + longueurMoyenne);
		
		System.out.println("Les 20 mots les plus frequents sont " + getMotsPlusFrequents());
		System.out.println("Les 20 mots les moins frequents sont " + getMotsMoinsFrequents());

		getKhi(); // On lance les calculs des khi
		
		System.out.println("Mots les plus significatif");
		System.out.println(getMotsPlusSignificatifs());
		System.out.println("Mots les moins significatif");
		System.out.println(getMotsMoinsSignificatifs());
	}

	
	/**
	 * Méthode qui récupère les 20 mots les plus  fréquents, toute classe confondue.
	 * @param motsTotal
	 * @return
	 * @throws IOException 
	 */
	public ArrayList<String> getMotsPlusFrequents () throws IOException {
		ArrayList<String> mots = new ArrayList<String>(21);
		HashMap<String, Integer> motsTotal = new HashMap<String, Integer>();

		for (Categorie s : statsParClasses.values()){
			motsTotal.putAll(s.getMotsOcc());
		}

		mots = Tri.getNMotsPlusFrequents(motsTotal, 20);
		
		// On enregistre les mots dans un fichier
		ecrireFichier("./mot_plus_frequents.txt", mots);
		
		return mots;
	}

	
	/**
	 * Méthode qui récupère les 20 mots les moins fréquents, toute classe confondue.
	 * @return 20 mots moins frequents
	 * @throws IOException 
	 */
	public ArrayList<String> getMotsMoinsFrequents () throws IOException {
		ArrayList<String> mots = new ArrayList<String>(20);
		HashMap<String, Integer> motsTotal = new HashMap<String, Integer>();


		for (Categorie s : statsParClasses.values()){
			motsTotal.putAll(s.getMotsOcc());
		}

		mots = Tri.getNMotsMoinsFrequents(motsTotal, 20);
		// On enregistre les mots dans un fichier
		ecrireFichier("./mot_moins_frequents.txt", mots);
		
		return mots;
	}


	/**
	 * Méthode qui retourne une hashmap contenant pour chaque polarité un arraylist avec les 
	 * 20 mots les plus significattif de leurs classes.
	 * @return
	 */
	public HashMap<String, ArrayList<String>> getMotsPlusSignificatifs() {
		if (null==motsPlusSignificatifs)
			getKhi();
		return motsPlusSignificatifs;
	}

	/**
	 * Méthode qui retourne une hashmap contenant pour chaque polarité un arraylist avec les 
	 * 20 mots les moins significattif de leurs classes.
	 * @return 20 mots moins significatifs
	 */
	public HashMap<String, ArrayList<String>> getMotsMoinsSignificatifs() {
		if (null==motsMoinsSignificatifs)
			getKhi();
		return motsMoinsSignificatifs;
	}

	/**
	 * Méthode qui retourne les valeurs des khi2 de tous nos mots en fonction de la polarité.
	 * (par la méthode du khi2).
	 */
	public void getKhi () {

		double A, B, C, D, a, b, c, d, C1, C2, L1, L2;

		HashMap <String, Double> khi2; // Contient pour chaque mot d'une classe sa valeur de khi2
		motsPlusSignificatifs = new HashMap<String, ArrayList<String>>();
		motsMoinsSignificatifs = new HashMap<String, ArrayList<String>>();
		
		int nbTotalTweet = 0;
		int nbTweetAutreCategorie = 0;
		double valKhi;

		// Pour chaque classe de polarite, nous allons compter le nombre total de tweets
		for (Categorie s : statsParClasses.values()){

			nbTotalTweet += s.getNbTweets();

		}
		System.out.println("Calcul des khi en cours....");
		// Pour chaque classe de polarite
		for (Categorie s : statsParClasses.values()){
			khi2 = new HashMap<String, Double>();
			nbTweetAutreCategorie = getNbTweetTotalAutreCategorie(s.getPolarite());
			//if (s.getPolarite().equals("negative")){
			//System.out.println("Polarité : " + s.getPolarite());
			// Pour chaque mots de cette classe
			//for (Entry<String, Integer> i : s.getMotsOcc().entrySet()){
			for (String mot : Extraction.getMots()){
				//if (i.getKey().equals("google")){
				//if (mot.equals("google")){

				// nombre de tweet dans lequel il apparait dans cette polarite
				//	a = (double)s.getNbTweetCategorie(i.getKey()) ;
				a = (double)s.getNbTweetCategorie(mot) ;

				// le nombre de tweet de cette classe dans lequel il n'apparait pas
				b = (double)s.getNbTweets() - a;

				// le nombre de tweet des autres polarité dans lequel il apparait
				//	c = (double)getNbTweetAutreCategorie(i.getKey(), s.getPolarite());
				c = (double)getNbTweetAutreCategorie(mot, s.getPolarite());

				// le nombre de tweet des autres classes dans lequel il n'apparait pas
				d = (double)nbTweetAutreCategorie - c;	

				C1 = (a+c);
				C2 = (b+d);
				L1 = (a+b);
				L2 = (c+d);

				A = (C1*L1) / (double)nbTotalTweet;
				B = (C2*L1) / (double)nbTotalTweet;
				C = (C1*L2) / (double)nbTotalTweet;
				D = (C2*L2) / (double)nbTotalTweet;


				//System.out.println("Valeurs : a-" + a + " b-" + b + " c-" + c + "-d " + d 
				//+ "\t a' : " + A + " b' : " + B + " c' : " + C + " d' : " + D);
				// On calcul la valeur de khi2 pour ce mot de cette classe
				valKhi = (Math.pow((a-A),2)/A) + (Math.pow((b-B),2)/B) + (Math.pow((c-C),2)/C) + (Math.pow((d-D),2)/D)  ;

				//System.out.println("vaut : " + i.getKey() + " .:. " +valKhi);
				//System.out.println("blublu");
				// On insere dans la Map
				//	khi2.put(i.getKey(), valKhi);
				khi2.put(mot, valKhi);
				//}			// if mot
			}
			motsPlusSignificatifs.put(s.getPolarite(), Tri.getNMotsPlusSignificatif(khi2, 20));
			motsMoinsSignificatifs.put(s.getPolarite(), Tri.getNMotsMoinsSignificatif(khi2, 20));
			//System.out.println(Tri.getNMotsPlusSignificatif(khi2, 20));
			//}			// if polarité
			// On recupere les 20 mots les plus significatifs
			//afficheMeilleursResultats(khi2);
		}




	}

	/**
	 * Retourne le nombre de tweet des autres categorie que celle de polarite
	 * @param polarite
	 * @return
	 */
	private Integer getNbTweetTotalAutreCategorie(String polarite) {
		int nbTweet = 0;
		for (Categorie s : statsParClasses.values()){
			if (!s.getPolarite().equals(polarite)){
				nbTweet += s.getNbTweets();
			}
		}
		return nbTweet;
	}

	private Integer getNbTweetAutreCategorieNonPresent(String mot, String polarite) {
		int nbTweet = 0;

		for (Categorie s : statsParClasses.values()){
			if (!s.getPolarite().equals(polarite)){
				nbTweet += s.getNbTweetNonPresent(mot);
			}
		}

		return nbTweet;
	}

	/**
	 * Méthode qui retourne le nombre de tweet des autres polarité dans lequel il apparait
	 * @param mot
	 * @param polarite
	 * @return
	 */
	private Integer getNbTweetAutreCategorie(String mot, String polarite) {
		int nbTweet = 0;

		for (Categorie s : statsParClasses.values()){
			if (!s.getPolarite().equals(polarite)){
				nbTweet += s.getNbTweetCategorie(mot);
			}
		}

		return nbTweet;
	}


	/**
	 * Méthode qui calcul le nombre de classe de polarité dans lequel un mot apparait.
	 * @param mot
	 * @return nombre classes
	 */
	public Integer getNbClassesMot (String mot) {
		int nbClasses = 0;

		// Pour chaque classe de polarite
		for (Categorie s : statsParClasses.values()){
			if (s.getMotsOcc().containsKey(mot))
				nbClasses++;
		}

		return nbClasses;
	}

	/**
	 * Méthode qui récupère le nombre d'occurences totale dans toutes les classes
	 * de polarité (hormis celles de test).
	 * @param mot
	 * @return nombre occurences
	 */
	public Integer getOccTotalMot(String mot) {

		int nbOccTotal = 0;
		// Pour chaque classe de polarite
		for (Categorie s : statsParClasses.values()){
			if (s.getMotsOcc().containsKey(mot))
				nbOccTotal += s.getMotsOcc().get(mot);
		}
		return nbOccTotal;
	}
	
	
	/**
	 * Méthode qui va ecrire data dans le fichier nomFic.
	 * @param nom
	 * @param data
	 * @throws IOException 
	 */
	public void ecrireFichier (String nomFic, ArrayList<String> data) throws IOException {
		
		FileWriter fw = new FileWriter(nomFic);
		
		// On ecrit tous les mots contenus dans data
		for (String mot : data) {
			fw.write(mot + "\n");
		}
		
		fw.close();
	}
	
	
	public HashMap<String, Categorie> getStatsParClasses() {
		return statsParClasses;
	}

}

